参数装饰器
概述
在 TypeScript 中,装饰器是一种特殊类型的声明,它可以附加到类声明、方法、访问器、属性或参数上。装饰器提供了一种方式来修改或扩展类的行为,而无需修改类的源代码。参数装饰器是装饰器的一种,专门用于修饰函数或方法的参数。
参数装饰器的基本概念
参数装饰器可以用来观察、修改或替换参数的定义。它们通常用于日志记录、验证、依赖注入等场景。参数装饰器不能直接修改参数的值,但可以通过修改类的元数据来影响参数的行为。
参数装饰器的语法
参数装饰器是一个函数,它接收三个参数:
target: 对于静态成员来说是类的构造函数,对于实例成员来说是类的原型对象。propertyKey: 成员的名字(字符串或符号)。parameterIndex: 参数在函数参数列表中的索引。
参数装饰器的返回值会被忽略。
示例代码
function logParameter(target: any, propertyKey: string, parameterIndex: number) {
console.log(`Decorating parameter ${parameterIndex} of method ${propertyKey} in class ${target.constructor.name}`);
}
class Example {
greet(@logParameter name: string) {
console.log(`Hello, ${name}!`);
}
}
const example = new Example();
example.greet("Alice");
输出
Decorating parameter 0 of method greet in class Example
Hello, Alice!
在这个例子中,logParameter 是一个参数装饰器,它会在 greet 方法的 name 参数上被调用。装饰器函数会输出参数的索引和方法的名称。
参数装饰器的应用场景
1. 日志记录
参数装饰器可以用于记录方法调用时的参数信息,这在调试和日志记录中非常有用。
function logParameter(target: any, propertyKey: string, parameterIndex: number) {
const originalMethod = target[propertyKey];
target[propertyKey] = function (...args: any[]) {
console.log(`Parameter at index ${parameterIndex}:`, args[parameterIndex]);
return originalMethod.apply(this, args);
};
}
class Example {
greet(@logParameter name: string) {
console.log(`Hello, ${name}!`);
}
}
const example = new Example();
example.greet("Alice");
2. 参数验证
参数装饰器可以用于验证参数的类型或值,确保它们符合预期的条件。
function validateParameter(target: any, propertyKey: string, parameterIndex: number) {
const originalMethod = target[propertyKey];
target[propertyKey] = function (...args: any[]) {
const param = args[parameterIndex];
if (typeof param !== 'string' || param.length === 0) {
throw new Error(`Invalid parameter at index ${parameterIndex}`);
}
return originalMethod.apply(this, args);
};
}
class Example {
greet(@validateParameter name: string) {
console.log(`Hello, ${name}!`);
}
}
const example = new Example();
example.greet(""); // 抛出错误
3. 依赖注入
参数装饰器可以用于实现依赖注入,自动将依赖项注入到方法的参数中。
const dependencies = new Map<string, any>();
function inject(dependencyName: string) {
return function (target: any, propertyKey: string, parameterIndex: number) {
const originalMethod = target[propertyKey];
target[propertyKey] = function (...args: any[]) {
args[parameterIndex] = dependencies.get(dependencyName);
return originalMethod.apply(this, args);
};
};
}
dependencies.set('logger', console);
class Example {
greet(@inject('logger') logger: Console) {
logger.log("Hello, world!");
}
}
const example = new Example();
example.greet(); // 输出 "Hello, world!"
实践练习
练习 1: 日志记录装饰器
编写一个参数装饰器,用于记录方法调用时的所有参数。
function logAllParameters(target: any, propertyKey: string, parameterIndex: number) {
const originalMethod = target[propertyKey];
target[propertyKey] = function (...args: any[]) {
console.log(`Parameters:`, args);
return originalMethod.apply(this, args);
};
}
class Example {
greet(@logAllParameters name: string, @logAllParameters age: number) {
console.log(`Hello, ${name}! You are ${age} years old.`);
}
}
const example = new Example();
example.greet("Alice", 30);
练习 2: 参数验证装饰器
编写一个参数装饰器,用于验证参数是否为正整数。
function validatePositiveInteger(target: any, propertyKey: string, parameterIndex: number) {
const originalMethod = target[propertyKey];
target[propertyKey] = function (...args: any[]) {
const param = args[parameterIndex];
if (typeof param !== 'number' || param <= 0 || !Number.isInteger(param)) {
throw new Error(`Invalid parameter at index ${parameterIndex}`);
}
return originalMethod.apply(this, args);
};
}
class Example {
greet(@validatePositiveInteger age: number) {
console.log(`You are ${age} years old.`);
}
}
const example = new Example();
example.greet(-5); // 抛出错误
练习 3: 依赖注入装饰器
编写一个参数装饰器,用于将一个配置对象注入到方法中。
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000
};
function injectConfig(target: any, propertyKey: string, parameterIndex: number) {
const originalMethod = target[propertyKey];
target[propertyKey] = function (...args: any[]) {
args[parameterIndex] = config;
return originalMethod.apply(this, args);
};
}
class Example {
fetchData(@injectConfig config: any) {
console.log(`Fetching data from ${config.apiUrl} with timeout ${config.timeout}`);
}
}
const example = new Example();
example.fetchData(); // 输出 "Fetching data from https://api.example.com with timeout 5000"
总结
参数装饰器是 TypeScript 中强大的工具,可以用于日志记录、参数验证、依赖注入等多种场景。通过理解和实践参数装饰器,你可以更好地掌握 TypeScript 的高级特性,并在实际项目中灵活应用。
希望这篇教程能帮助你更好地理解和使用参数装饰器。继续探索 TypeScript 的世界,你会发现更多有趣和强大的功能!